/*
 Copyright 2009 Abdulla Abdurakhmanov (abdulla@latestbit.com)
 Original sources are available at www.latestbit.com

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

#ifndef SOCKETMULTIPLEXER_HPP
#define SOCKETMULTIPLEXER_HPP

#include "OSSocketDefs.hpp"
#include "smartobjects/SmartObjectsDefs.hpp"


namespace smartobjects {
	namespace sockets {

		class SocketMultiplexer {
		public:
			typedef boost::shared_ptr < SocketMultiplexer > SharedPtr;
			typedef boost::function< void (bool) > ReaderHandler;
			typedef boost::function< void (void) > AcceptorHandler;
			typedef boost::function< void (bool) > ConnectorHandler;
			typedef boost::function< void (void) > KeepAliveHandler;

		public:
			SO_DLLPRFX SocketMultiplexer();
			SO_DLLPRFX virtual ~SocketMultiplexer(void);

			SO_DLLPRFX void addSocketReader(Socket hSocket, ReaderHandler pfHandler, KeepAliveHandler pfKeepAliveHandler);
			SO_DLLPRFX void removeSocketReader(Socket hSocket);

			SO_DLLPRFX void addSocketAcceptor(Socket hSocket, AcceptorHandler pfHandler);
			SO_DLLPRFX void removeSocketAcceptor(Socket hSocket);

			SO_DLLPRFX void addSocketConnector(Socket hSocket, ConnectorHandler pfHandler);
			SO_DLLPRFX void removeSocketConnector(Socket hSocket);

			SO_DLLPRFX bool isFull();

		protected:
			class Handler {
			public:
				Handler() :
					m_hSocket (-1), m_pfReaderHandler (NULL), m_pfAcceptorHandler ( NULL ), m_pfConnectorHandler (NULL), m_pfKeepAliveHandler(NULL),
					m_bIsRemoved(false), m_bReaderAction(false), m_bAcceptorAction(false), m_bConnectorAction(false) {

				}

				ReaderHandler getReaderHandler() {
					return m_pfReaderHandler;
				}

				void setReaderHandler(ReaderHandler pfHandler) {
					m_pfReaderHandler = pfHandler;
					setReaderAction (true);
				}


				bool hasReaderHandler() {
					return getReaderHandler() != NULL;
				}

				AcceptorHandler getAcceptorHandler() {
					return m_pfAcceptorHandler;
				}

				void setAcceptorHandler(AcceptorHandler pfHandler) {
					m_pfAcceptorHandler = pfHandler;
					setAcceptorAction (true);
				}

				bool hasAcceptorHandler() {
					return getAcceptorHandler() != NULL;
				}

				ConnectorHandler getConnectorHandler() {
					return m_pfConnectorHandler;
				}

				void setConnectorHandler(ConnectorHandler pfHandler) {
					m_pfConnectorHandler = pfHandler;
					setConnectorAction (true);
				}

				bool hasConnectorHandler() {
					return getConnectorHandler() != NULL;
				}

				KeepAliveHandler getKeepAliveHandler() {
					return m_pfKeepAliveHandler;
				}

				void setKeepAliveHandler(KeepAliveHandler pfHandler) {
					m_pfKeepAliveHandler = pfHandler;
				}


				bool hasKeepAliveHandler() {
					return getKeepAliveHandler() != NULL;
				}


				bool isRemoved() {
					return this->m_bIsRemoved;
				}

				void setRemoved(bool bValue) {
					this->m_bIsRemoved = bValue;
				}

				void setSocket(Socket hSocket) {
					m_hSocket = hSocket;
				}

				Socket getSocket() {
					return m_hSocket;
				}

				void setReaderAction (bool bValue) {
					m_bReaderAction = bValue;
				}

				bool isReaderAction () {
					return m_bReaderAction;
				}

				void setAcceptorAction (bool bValue) {
					m_bAcceptorAction = bValue;
				}

				bool isAcceptorAction () {
					return m_bAcceptorAction;
				}

				void setConnectorAction (bool bValue) {
					m_bConnectorAction = bValue;
				}

				bool isConnectorAction () {
					return m_bConnectorAction;
				}

			private:
				Socket m_hSocket;
				ReaderHandler m_pfReaderHandler;
				AcceptorHandler m_pfAcceptorHandler;
				ConnectorHandler m_pfConnectorHandler;
				KeepAliveHandler m_pfKeepAliveHandler;

				bool m_bIsRemoved;
				bool m_bReaderAction;
				bool m_bAcceptorAction;
				bool m_bConnectorAction;
			};

		protected:
			typedef std::map < Socket, Handler > Handlers;
			typedef std::list < Handler > HandlerList;

			SO_DLLPRFX void run();
			SO_DLLPRFX void processReaderHandlers ( SocketSet& oReadersSet, SocketSet& oExceptsSet );
			SO_DLLPRFX void processWriterHandlers ( SocketSet& oWritersSet );
			SO_DLLPRFX void processExceptHandlers ( SocketSet& oExceptsSet );
			SO_DLLPRFX void createFDSet(Handlers& oHandlers, SocketSet& oSocketSet);

			SO_DLLPRFX void postProcessHandlersQueue ( );
			SO_DLLPRFX void postProcessKeepAliveCycle ( );

		private:
			static const int WAIT_EVENT_INTERVAL_MILLISEC = 50;

			Handlers m_mReaderHandlers, m_mWriterHandlers, m_mExceptHandlers;
			HandlerList m_aPostProcessQueue;
			boost::recursive_mutex m_mxHandlers;


			boost::thread* m_poThread;
			int m_nHighestDescriptor;
			bool m_bStopFlag;
			bool m_bHandlersRunStatus;
		};
	}
}

#endif // SOCKETMULTIPLEXER_HPP
